#pragma once
// 对epoll模型（IO多路转接）的接口的封装
#include <sys/epoll.h> //epoll模型创建需要包含的头文件
#include "log.hpp"     //日志打印
#include"nocopy.hpp" //防止拷贝
extern Log lg;         // 声明变量（在log.hpp创建的）
#define EPOLL_CREATE_ERR -1
static const int defaultfd = -1;
class Epoll:public nocopy
{
public:
    Epoll(const int &epollfd = defaultfd)
        : epoll_fd(epollfd)
    {
        //方法尽量不要写到构造里面
    }
    void EpollCreate()
    {
        epoll_fd = epoll_create(222); // 创建epoll模型，size参数被忽略但必须>0
        if (epoll_fd == -1)           // 创建失败返回-1，并设置errno错误码
        {
            lg(FATAL, "Epollfd create error！！ errmessige is:%s", strerror(errno));
            exit(EPOLL_CREATE_ERR); // epoll创建失败终止进程
        }
    }
    int EpollWait(struct epoll_event events[], int maxevents, int timeout) // 第一个参数为输出型参数，传进来捞数据出去
    {
        // maxevents为自己设置的一次想捞几个数据上来，如果一次没捞完下次继续捞
        int n = epoll_wait(epoll_fd, events, maxevents, timeout);
        // 返回值为就绪事件对应的fd个数
        return n;
    }
    int EpollUpdate(int oper, int fd, uint32_t event) // 更新修改数据
    {
        // 更新哪个文件描述符？怎么更新？更新什么事件？
        // 对oper进行判断，看看是什么操作，如果是删除
        int n = 0;
        if (oper == EPOLL_CTL_DEL)
        {
            n = epoll_ctl(epoll_fd, oper, fd, nullptr); // 最后一个参数设为nullptr表示是一个删除操作
            if (n != 0)
            {
                lg(WARNING, "Epoll delete error!! errmessige is:%s", strerror(errno));
            }
        }
        else
        {
            // EPOLL_CTL_MOD /EPOLL_CTL_ADD
            struct epoll_event ev;
            ev.events = event;
            ev.data.fd=fd;//为了往后用到
            n = epoll_ctl(epoll_fd, oper, fd, &ev);
            if (n != 0)
            {
                lg(WARNING, "Epoll_ctl error!! errmessige is:%s", strerror(errno));
            }
        }
        return n;
    }
    ~Epoll()
    {
        if(epoll_fd>0)
        close(epoll_fd);
    }

private:
    int epoll_fd; // 创建成功返回一个非负文件描述符
};